﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using CLDataAppManagement;
using CLDataAppManagementTS;
using MQTTnet;
using NationalInstruments.TestStand.Interop.API;
using Newtonsoft.Json.Linq;

namespace CLVisionEICS
{
    public class CLEICSClientCaller
    {
        static ICLEICSClient clEICSCallerInstance = null;

        private static bool CheckInstance(out int ErrorCode, out string ErrorText, out bool Occurred, string methodName)
        {
            if (clEICSCallerInstance == null)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{methodName}: MQTT客户端对象为null！请检查IntMqttClient初始化是否执行成功！";
                Occurred = true;
                return false;
            }
            ErrorCode = 0;
            ErrorText = $"{nameof(CLEICSClientCaller)}:{methodName}: Start!";
            Occurred = false;
            return true;
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="server">服务器Ip地址</param>
        /// <param name="port">服务器端口号</param>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="topicName">订阅主题</param>
        /// <param name="clientId"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <param name="cdatFilePath"></param>
        /// <returns></returns>
        public static bool IntMqttClient(string server, int port, string username, string password, string topicName, string clientId, out int ErrorCode, out string ErrorText, out bool Occurred, string cdatFilePath = null)
        {
            ErrorCode = 0;
            ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(IntMqttClient)}: Start!";
            Occurred = false;
            try
            {
                clEICSCallerInstance = CLEICSClientFactory.CreateMQTTClient();
                if (clEICSCallerInstance == null)
                {
                    ErrorCode = -1;
                    ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(IntMqttClient)}: 创建MQTT客户端对象失败！请检查dll放置路径是否有误！";
                    Occurred = true;
                    return false;
                }
                bool ret = clEICSCallerInstance.IntMqttClient(server, port, username, password, topicName, clientId, out ErrorCode, out ErrorText, cdatFilePath);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }

                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(IntMqttClient)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(IntMqttClient)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 发布数据到指定主题
        /// </summary>
        /// <param name="topicName"></param>
        /// <param name="propertyObject"></param>
        /// <param name="qos"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <returns></returns>
        public static bool PublishData(string topicName, MQTTnet.Protocol.MqttQualityOfServiceLevel qos, out int ErrorCode, out string ErrorText, out bool Occurred)
        {
            if (!CheckInstance(out ErrorCode, out ErrorText, out Occurred, nameof(PublishData)))
                return false;
            try
            {
                // JToken jToken = new JObject();
                //  DataAppManagementTS.Getdata(propertyObject, ref jToken);

                JToken jToken = clEICSCallerInstance.eicsJson;
                string sendMsg = jToken.ToString();
                bool ret = clEICSCallerInstance.PublishData(topicName, sendMsg, qos, out ErrorCode, out ErrorText);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(PublishData)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(PublishData)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 订阅主题
        /// </summary>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <param name="topicNames"></param>
        /// <returns></returns>
        public static bool SubscribeTopic(out int ErrorCode, out string ErrorText, out bool Occurred, params string[] topicNames)
        {
            if (!CheckInstance(out ErrorCode, out ErrorText, out Occurred, nameof(SubscribeTopic)))
                return false;
            try
            {
                bool ret = clEICSCallerInstance.SubscribeTopic(out ErrorCode, out ErrorText, topicNames);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SubscribeTopic)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SubscribeTopic)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 取消订阅主题
        /// </summary>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <param name="topicNames"></param>
        /// <returns></returns>
        public static bool UnsubscribeTopic(out int ErrorCode, out string ErrorText, out bool Occurred, params string[] topicNames)
        {
            if (!CheckInstance(out ErrorCode, out ErrorText, out Occurred, nameof(UnsubscribeTopic)))
                return false;
            try
            {
                bool ret = clEICSCallerInstance.UnsubscribeTopic(out ErrorCode, out ErrorText, topicNames);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(UnsubscribeTopic)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(UnsubscribeTopic)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 断开MQTT客户端连接
        /// </summary>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <returns></returns>
        public static bool DisconnectMqttClient(out int ErrorCode, out string ErrorText, out bool Occurred)
        {
            if (!CheckInstance(out ErrorCode, out ErrorText, out Occurred, nameof(DisconnectMqttClient)))
                return false;
            try
            {
                bool ret = clEICSCallerInstance.DisconnectMqttClient(out ErrorCode, out ErrorText);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(DisconnectMqttClient)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(DisconnectMqttClient)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 从PropertyObject对象中读取数据
        /// </summary>
        /// <param name="propertyObject"></param>
        /// <param name="filePath"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <returns></returns>
        private static bool ReadDataFromFile(PropertyObject propertyObject, string filePath, out int ErrorCode, out string ErrorText, out bool Occurred)
        {
            if (!CheckInstance(out ErrorCode, out ErrorText, out Occurred, nameof(ReadDataFromFile)))
                return false;
            try
            {
                JToken jToken = null;
                DataAppManagementTS.LoadFile(filePath, out jToken, out ErrorCode, out ErrorText, out Occurred);

                DataAppManagementTS.AddJTokenToPropertyObject(jToken, ref propertyObject, out ErrorCode, out ErrorText);

                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(ReadDataFromFile)}: End!";
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(ReadDataFromFile)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 将PropertyObject对象中的数据写入到文件
        /// </summary>
        /// <param name="propertyObject"></param>
        /// <param name="filePath"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <returns></returns>
        private static bool WriteDataToFile(PropertyObject propertyObject, string filePath, out int ErrorCode, out string ErrorText, out bool Occurred)
        {
            if (!CheckInstance(out ErrorCode, out ErrorText, out Occurred, nameof(WriteDataToFile)))
                return false;
            try
            {
                JToken jToken = new JObject();
                DataAppManagementTS.Getdata(propertyObject, ref jToken);
                DataAppManagementTS.SaveFile(filePath, jToken, out ErrorCode, out ErrorText, out Occurred);

                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(WriteDataToFile)}: End!";
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(WriteDataToFile)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }
        public static bool WriteEICSToFile(string filePath, out int ErrorCode, out string ErrorText, out bool Occurred)
        {
            if (!CheckInstance(out ErrorCode, out ErrorText, out Occurred, nameof(WriteEICSToFile)))
                return false;
            try
            {
                using (FileStream stream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.Write))
                {
                    using (StreamWriter streamWriter = new StreamWriter(stream))
                    {
                        streamWriter.Write(clEICSCallerInstance.eicsJson.ToString());
                    }
                }


                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(WriteEICSToFile)}: End!";
                return true;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(WriteEICSToFile)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 接收数据并带有超时机制
        /// </summary>
        /// <param name="receivedMessage"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <param name="timeoutMs"></param>
        /// <param name="pollIntervalMs"></param>
        /// <returns></returns>
        public static bool ReceiveDataWithTimeout(out string receivedMessage, out int ErrorCode, out string ErrorText, out bool Occurred, int timeoutMs = 3000, int pollIntervalMs = 50)
        {
            receivedMessage = string.Empty;
            if (!CheckInstance(out ErrorCode, out ErrorText, out Occurred, nameof(ReceiveDataWithTimeout)))
                return false;
            try
            {
                bool ret = clEICSCallerInstance.ReceiveDataWithTimeout(out receivedMessage, out ErrorCode, out ErrorText);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(ReceiveDataWithTimeout)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(ReceiveDataWithTimeout)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 设置EICS值，通过Key来设置
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <returns></returns>
        public static bool SetEICSValueByKey(string key, object value, out int ErrorCode, out string ErrorText, out bool Occurred)
        {
            ErrorCode = 0;
            ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByKey)}: Start!";
            Occurred = false;
            try
            {
                clEICSCallerInstance = CLEICSClientFactory.CreateMQTTClient();
                if (clEICSCallerInstance == null)
                {
                    ErrorCode = -1;
                    ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByKey)}: 创建MQTT客户端对象失败！请检查dll放置路径是否有误！";
                    Occurred = true;
                    return false;
                }
                bool ret = clEICSCallerInstance.SetEICSValueByKey(key, value, out ErrorCode, out ErrorText);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByKey)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByKey)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 设置EICS值，通过PropertyObject的Key来设置
        /// </summary>
        /// <param name="keyValue"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <returns></returns>
        public static bool SetEICSValueByKey(PropertyObject keyValue, out int ErrorCode, out string ErrorText, out bool Occurred)
        {
            ErrorCode = 0;
            ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByKey)}: Start!";
            Occurred = false;
            try
            {
                clEICSCallerInstance = CLEICSClientFactory.CreateMQTTClient();
                if (clEICSCallerInstance == null)
                {
                    ErrorCode = -1;
                    ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByKey)}: 创建MQTT客户端对象失败！请检查dll放置路径是否有误！";
                    Occurred = true;
                    return false;
                }
                bool ret = clEICSCallerInstance.SetEICSValueByKey(keyValue, out ErrorCode, out ErrorText);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByKey)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByKey)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 设置EICS值，通过PropertyObject的Key来设置多个值
        /// </summary>
        /// <param name="keysValues"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <returns></returns>
        public static bool SetEICSValuesByKeys(PropertyObject keysValues, out int ErrorCode, out string ErrorText, out bool Occurred)
        {
            ErrorCode = 0;
            ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValuesByKeys)}: Start!";
            Occurred = false;
            try
            {
                clEICSCallerInstance = CLEICSClientFactory.CreateMQTTClient();
                if (clEICSCallerInstance == null)
                {
                    ErrorCode = -1;
                    ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValuesByKeys)}: 创建MQTT客户端对象失败！请检查dll放置路径是否有误！";
                    Occurred = true;
                    return false;
                }
                bool ret = clEICSCallerInstance.SetEICSValuesByKeys(keysValues, out ErrorCode, out ErrorText);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValuesByKeys)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValuesByKeys)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }

        /// <summary>
        /// 设置EICS值，通过字符串数组来设置
        /// </summary>
        /// <param name="valueString"></param>
        /// <param name="ErrorCode"></param>
        /// <param name="ErrorText"></param>
        /// <param name="Occurred"></param>
        /// <returns></returns>
        public static bool SetEICSValueByArrayString(PropertyObject valueString, out int ErrorCode, out string ErrorText, out bool Occurred)
        {
            ErrorCode = 0;
            ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByArrayString)}: Start!";
            Occurred = false;
            try
            {
                clEICSCallerInstance = CLEICSClientFactory.CreateMQTTClient();
                if (clEICSCallerInstance == null)
                {
                    ErrorCode = -1;
                    ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByArrayString)}: 创建MQTT客户端对象失败！请检查dll放置路径是否有误！";
                    Occurred = true;
                    return false;
                }
                string value = valueString.GetValString("", 0);
                bool ret = clEICSCallerInstance.SetEICSValueByArrayString(value, out ErrorCode, out ErrorText);
                if (ErrorCode == -1)
                {
                    Occurred = true;
                    return false;
                }
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByArrayString)}: End!";
                return ret;
            }
            catch (Exception ex)
            {
                ErrorCode = -1;
                ErrorText = $"{nameof(CLEICSClientCaller)}:{nameof(SetEICSValueByArrayString)}: Fail! " + ex.Message;
                Occurred = true;
                return false;
            }
        }
    }
}
